#if !defined(ximera_xml_xmliterator_hpp)
#define ximera_xml_xmliterator_hpp

// -----------------------------------------------------------

#include <ximera/xml/xmlnode.hpp>
#include <ximera/assert.hpp>

namespace ximera { namespace xml
{
    template <typename NodeType>
    class XmlIterator
    {
    public:
        XmlIterator(XmlNode& node)
            : _node(&node), _useName(false), _done(false)
        {
            _current = _node->childBegin();
            setNext();
        }

        XmlIterator(XmlNode& node, String const& name)
            : _node(&node), _name(name), _useName(true), _done(false)
        {
            _current = _node->childBegin();
            setNext();
        }

        XmlIterator(XmlNode const* node)
            : _node(node), _useName(false), _done(false)
        {
            XIMERA_ASSERT_DEF(node);
            _current = _node->childBegin();
            setNext();
        }

        XmlIterator(XmlNode const* node, String const& name)
            : _node(node), _name(name), _useName(true), _done(false)
        {
            XIMERA_ASSERT_DEF(node);
            _current = _node->childBegin();
            setNext();
        }

        NodeType* get() const
        {
            return static_cast<NodeType*>(_current->get());
        }

        NodeType* operator*() const
        {
            return static_cast<NodeType*>(_current->get());
        }

        NodeType* operator->() const
        {
            return static_cast<NodeType*>(_current->get());
        }

        XmlIterator& operator++()
        {
            ++_current;
            setNext();
            return *this;
        }

        XmlIterator& operator--()
        {
            --_current;
            setPrior();
            return *this;
        }

        operator void*() const
        {
            return _done ? 0 : reinterpret_cast<void*>(1);
        }

    private:
        XmlNode const* _node;
        String _name;

        XmlNode::ChildConstIterator _current;
        
        bool _useName;
        bool _done;        

        void setPrior()
        {
            if (_done) 
                return;

            while (_current != _node->childBegin())
            {
                NodeType* curNode = dynamic_cast<NodeType*>(_current->get());
                if (curNode && (!_useName || curNode->value() == _name))
                    return;

                --_current;
            }

            _done = true;
        }
        
        void setNext()
        {
            if (_done)
                return;

            while (_current != _node->childEnd())
            {
                NodeType* curNode = dynamic_cast<NodeType*>(_current->get());
                if (curNode && (!_useName || curNode->value() == _name))
                    return;

                ++_current;
            }

            _done = true;
        }
    };

    typedef XmlIterator<XmlNode> XmlNodeIterator;
}}

// -----------------------------------------------------------

#endif
